#include "graph.h"
#include <time.h>
#ifdef _WIN32
#include <direct.h>
#else
#include <sys/stat.h>
#endif

// Function declarations
Graph* load_graph_from_csv(const char* nodes_file, const char* edges_file);
Schedule* generate_initial_schedule(Graph* g);
bool is_l0_schedule_valid(const int* schedule, int length, const Graph* g);
Schedule* optimizer_random_sampling(const Schedule* initial, const Graph* g, const OptOptions* opts, const char* output_dir);
Schedule* optimizer_systematic_search(const Schedule* initial, const Graph* g, const OptOptions* opts, const char* output_dir);

int main(int argc, char* argv[]) {
    printf("=== GMCM 2025 Problem 1: Core Scheduling Optimization ===\n\n");
    
    // Initialize random seed
    srand((unsigned int)time(NULL));
    
    // 1. Configuration - TEST PARAMETERS (快速测试用)
    OptOptions opts = {
        .iterations = 5000,           // Phase 1: 测试用减少迭代次数
        .batch_size = 200,             // Phase 1: 测试用减少批大小
        .patience = 200,              // Phase 1: 测试用减少耐心值
        .max_passes =300,             // Phase 2: 测试用减少搜索轮数  
        .time_limit_minutes = 30,      // 总时间限制: 30分钟 
        .num_threads = 8              // 线程数保持不变
    };
    
    printf("TEST CONFIGURATION (Fast Testing Mode):\n");
    printf("- Phase 1 iterations: %d (reduced for testing)\n", opts.iterations);
    printf("- Batch size: %d (reduced for testing)\n", opts.batch_size);
    printf("- Patience: %d (reduced for testing)\n", opts.patience);
    printf("- Phase 2 passes: %d (reduced for testing)\n", opts.max_passes);
    printf("- Time limit: %d minutes (short runtime)\n", opts.time_limit_minutes);
    
    #ifdef _OPENMP
    omp_set_num_threads(opts.num_threads);
    printf("- OpenMP threads: %d\n", opts.num_threads);
    #else
    printf("- Threading: Single thread (OpenMP not available)\n");
    #endif
    
    // 1.5. 重置性能统计
    reset_topological_check_stats();
    
    // 2. Determine input files and output directory
    const char* nodes_file = "data/CSV-version/Conv_Case0_Nodes.csv";
    const char* edges_file = "data/CSV-version/Conv_Case0_Edges.csv";
    const char* task_name = "Conv_Case0";
    const char* output_dir = "result/Problem1";  // 默认输出目录
    
    if (argc >= 4) {
        nodes_file = argv[1];
        edges_file = argv[2];
        task_name = argv[3];
        if (argc >= 5) {
            output_dir = argv[4];  // 如果指定了输出目录
        }
    }
    
    printf("\nCommand line arguments:\n");
    printf("- argc: %d\n", argc);
    if (argc >= 4) {
        printf("- Using specified files and task name\n");
    } else {
        printf("- Using default Conv_Case0 files\n");
    }
    
    printf("\nProcessing task: %s\n", task_name);
    printf("Loading data files:\n");
    printf("- Nodes: %s\n", nodes_file);
    printf("- Edges: %s\n", edges_file);
    printf("- Output directory: %s\n", output_dir);
    
    // 3. Load graph data
    double load_start = get_time_seconds();
    Graph* g = load_graph_from_csv(nodes_file, edges_file);
    
    if (!g) {
        printf("ERROR: Failed to load graph data\n");
        return 1;
    }
    
    double load_time = get_time_seconds() - load_start;
    printf("Data loading completed in %.2f seconds\n", load_time);
    print_graph_stats(g);
    
    // 4. Generate initial schedule
    printf("\n=== Generating Initial Schedule ===\n");
    double init_start = get_time_seconds();
    Schedule* initial = generate_initial_schedule(g);
    double init_time = get_time_seconds() - init_start;
    
    if (!initial) {
        printf("ERROR: Failed to generate initial schedule\n");
        free_graph(g);
        return 1;
    }
    
    printf("Initial schedule generated in %.2f seconds\n", init_time);
    printf("Initial schedule length: %d\n", initial->length);
    printf("Initial peak memory (V_stay): %d\n", initial->max_vstay);
    
    // Validate L0 constraints
    if (!is_l0_schedule_valid(initial->schedule, initial->length, g)) {
        printf("WARNING: Initial schedule violates L0 constraints!\n");
    } else {
        printf("L0 constraint validation: PASSED\n");
    }
    
    // 5. Two-phase optimization
    double total_start = get_time_seconds();
    
    printf("\n=== Two-Phase Optimization ===\n");
    printf("\n--- Phase 1: Broad Exploration ---\n");
    double phase1_start = get_time_seconds();
    Schedule* phase1_result = optimizer_random_sampling(initial, g, &opts, output_dir);
    double phase1_time = get_time_seconds() - phase1_start;
    
    printf("Phase 1 completed in %.2f seconds\n", phase1_time);
    printf("Phase 1 result: Score improved from %d to %d\n", 
           initial->max_vstay, phase1_result->max_vstay);
    
    // 在进入阶段二前，先将阶段一的结果落盘，避免阶段二中断导致无结果
    {
        // 确保输出目录存在 (创建必要的父目录)
        #ifdef _WIN32
        char parent_dir[256];
        snprintf(parent_dir, sizeof(parent_dir), "%s", output_dir);
        _mkdir(parent_dir);  // 尝试创建输出目录，如果已存在会忽略错误
        #else
        char parent_dir[256];
        snprintf(parent_dir, sizeof(parent_dir), "%s", output_dir);
        mkdir(parent_dir, 0777);  // 尝试创建输出目录，如果已存在会忽略错误
        #endif

        char schedule_filename_p1[512];
        snprintf(schedule_filename_p1, sizeof(schedule_filename_p1), "%s/%s_schedule_phase1.txt", output_dir, task_name);
        FILE* fp_p1 = fopen(schedule_filename_p1, "w");
        if (fp_p1) {
            for (int i = 0; i < phase1_result->length; i++) {
                fprintf(fp_p1, "%d\n", phase1_result->schedule[i]);
            }
            fclose(fp_p1);
            printf("[Safety] Phase 1 schedule saved to: %s\n", schedule_filename_p1);
        } else {
            printf("WARNING: Unable to save Phase 1 schedule to %s\n", schedule_filename_p1);
        }
    }

    printf("\n--- Phase 2: Deep Optimization ---\n");
    double phase2_start = get_time_seconds();
    Schedule* final_result = optimizer_systematic_search(phase1_result, g, &opts, output_dir);
    double phase2_time = get_time_seconds() - phase2_start;
    
    printf("Phase 2 completed in %.2f seconds\n", phase2_time);
    printf("Phase 2 result: Score improved from %d to %d\n", 
           phase1_result->max_vstay, final_result->max_vstay);
    
    double total_elapsed = get_time_seconds() - total_start;
    
    // 6. Final Results Summary
    printf("\n=== Final Optimization Results ===\n");
    printf("Initial solution score: %d\n", initial->max_vstay);
    printf("Phase 1 result score: %d\n", phase1_result->max_vstay);
    printf("Final optimized score: %d\n", final_result->max_vstay);
    
    if (initial->max_vstay > 0) {
        int improvement = initial->max_vstay - final_result->max_vstay;
        double improvement_pct = 100.0 * improvement / initial->max_vstay;
        printf("Total memory reduction: %d (%.2f%%)\n", improvement, improvement_pct);
    }
    
    printf("Total optimization time: %.2f seconds\n", total_elapsed);
    
    // 7. Generate Competition Format Output Files
    printf("\n=== Generating Competition Format Results ===\n");
    
    // Create result directory path (ensure exists)
    char result_dir[256];
    snprintf(result_dir, sizeof(result_dir), "%s", output_dir);
    
    // Generate schedule file: <task_name>_schedule.txt
    char schedule_filename[512];
    snprintf(schedule_filename, sizeof(schedule_filename), "%s/%s_schedule.txt", result_dir, task_name);
    
    FILE* schedule_fp = fopen(schedule_filename, "w");
    if (!schedule_fp) {
        printf("ERROR: Cannot create schedule output file: %s\n", schedule_filename);
    } else {
        // Write schedule in competition format (one node ID per line)
        for (int i = 0; i < final_result->length; i++) {
            fprintf(schedule_fp, "%d\n", final_result->schedule[i]);
        }
        fclose(schedule_fp);
        printf("Schedule result saved to: %s\n", schedule_filename);
    }
    
    // Generate summary file for reference
    char summary_filename[512];
    snprintf(summary_filename, sizeof(summary_filename), "%s/%s_summary.txt", result_dir, task_name);
    
    FILE* summary_fp = fopen(summary_filename, "w");
    if (summary_fp) {
        fprintf(summary_fp, "=== GMCM 2025 Problem 1 Results Summary ===\n");
        fprintf(summary_fp, "Task Name: %s\n", task_name);
        fprintf(summary_fp, "Graph Size: %d nodes, %d edges\n", g->num_nodes, g->num_edges);
        fprintf(summary_fp, "Initial V_stay: %d\n", initial->max_vstay);
        fprintf(summary_fp, "Phase 1 V_stay: %d\n", phase1_result->max_vstay);
        fprintf(summary_fp, "Final V_stay: %d\n", final_result->max_vstay);
        if (initial->max_vstay > 0) {
            int improvement = initial->max_vstay - final_result->max_vstay;
            double improvement_pct = 100.0 * improvement / initial->max_vstay;
            fprintf(summary_fp, "Improvement: %d (%.2f%%)\n", improvement, improvement_pct);
        }
        fprintf(summary_fp, "Total Time: %.2f seconds\n", total_elapsed);
        fprintf(summary_fp, "Phase 1 Time: %.2f seconds\n", phase1_time);
        fprintf(summary_fp, "Phase 2 Time: %.2f seconds\n", phase2_time);
        fclose(summary_fp);
        printf("Summary saved to: %s\n", summary_filename);
    }
    
    printf("\n=== Competition Results Generation Complete ===\n");
    printf("All files are ready for submission in the %s directory.\n", output_dir);
    
    // 7.5. 性能统计输出
    print_topological_check_stats();
    
    // 8. Cleanup
    free_schedule(initial);
    free_schedule(phase1_result);
    free_schedule(final_result);
    free_graph(g);
    
    return 0;
}
